package cmd

import (
	"illuminant/config"
	"illuminant/routes"
	"log"
	"os"
	"syscall"

	"github.com/fsnotify/fsnotify"
	"github.com/gin-gonic/gin"
	"github.com/kardianos/osext"
	"github.com/spf13/cobra"
)

var (
	isProd  bool
	port    int
	servCmd = &cobra.Command{
		Use:   "serv",
		Short: "server command",
		RunE: func(cmd *cobra.Command, args []string) error {
			if !isProd {
				gin.SetMode(gin.DebugMode)
				watcher, err := setupWatcher()
				if err != nil {
					return err
				}
				defer close(watcher)
			} else {
				gin.SetMode(gin.ReleaseMode)
			}

			if port > 0 {
				return routes.Routes(port)
			}

			cnf := config.Get()
			return routes.Routes(cnf.Server.Port)
		},
	}
)

func init() {
	servCmd.Flags().BoolVar(&isProd, "prod", false, "running in prod mode")
	servCmd.Flags().IntVar(&port, "port", -1, "server port")
}

func setupWatcher() (chan struct{}, error) {
	file, err := osext.Executable()
	if err != nil {
		return nil, err
	}
	log.Printf("watching %q\n", file)
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	done := make(chan struct{})
	go func() {
		select {
		case e := <-w.Events:
			log.Printf("watcher received: %v", e)
			err := syscall.Exec(file, os.Args, os.Environ())
			if err != nil {
				log.Fatal(err)
			}
		case err := <-w.Errors:
			log.Printf("watcher error: %+v", err)
		case <-done:
			log.Print("watcher shutting down")
			return
		}
	}()
	err = w.Add(file)
	if err != nil {
		return nil, err
	}
	return done, nil
}
